using System;
using System.Drawing;
using System.Collections.Generic;
using System.IO;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework;
using Ntx.GD;
using XNAColor = Microsoft.Xna.Framework.Graphics.Color;
using SystemColor = System.Drawing.Color;

namespace TileSetRender
{
    /// <summary>
    /// Parses Dune 2000 R16 files
    /// </summary>
    /// 
    public class R8Parser
    {
        #region Variables
        string filepath;
        BinaryReader r;
        List<Texture2D> textures;
        
        List<TileSetTile> tiles;
        GraphicsDevice device;
        XNAColor[] palette = new XNAColor[256];
        #endregion

        #region Properties
        public List<Texture2D> Textures
        {
            get { return textures; }
        }
        public List<TileSetTile> Tiles
        {
            get { return tiles; }
        }
        #endregion

        /// <summary>
        /// Begins parsing  an R16 file
        /// </summary>
        /// <param name="filepath">Location of the file</param>
        /// <param name="device">Graphics device (used for creating textures)</param>
        public R8Parser(string filepath, string paletteFilename, GraphicsDevice device)
        {
            this.filepath = filepath;
            this.device = device;

            LoadPalette(paletteFilename);

            r = new BinaryReader(File.Open(filepath, FileMode.OpenOrCreate));
            textures = new List<Texture2D>();
            tiles = new List<TileSetTile>();
            //Read textures 'til we can read no more.
            try
            {
                while (true)
                {
                    tiles.Add(ReadBlock());
                    //textures.Add(ReadBlock());
                }
            }
            catch { }
        }

        private void LoadPalette(string paletteFilename)
        {
            FileStream fs = new FileStream(paletteFilename, FileMode.Open);
            BinaryReader br = new BinaryReader(fs);
            for (int i = 0; i < 256; i++)
            {
                palette[i] = this.ReadColor(br);
            }
            br.Close();
            fs.Close();
        }

        private XNAColor ReadColor(BinaryReader br)
        {
            byte source;
            float converted;
            source = br.ReadByte();
            converted = (255.0f / 63.0f) * source;
            byte r = Convert.ToByte(converted);
            
            source = br.ReadByte();
            converted = (255.0f / 63.0f) * source;
            byte g = Convert.ToByte(converted);
            
            source = br.ReadByte();
            converted = (255.0f / 63.0f) * source;
            byte b = Convert.ToByte(converted);

            return new XNAColor(r, g, b);
        }

        /// <summary>
        /// Reads one block of information about a tile.
        /// </summary>
        /// <returns>A texture for that block. Later change this to a Tile class.</returns>
        private TileSetTile ReadBlock()
        {
            
            //If the block doesn't start with 0x01, then we've got issues :)
            if (r.ReadByte() != 1)
            {
                throw new Exception("Tried to read new block in " + filepath + " failed. Assertion error - block didn't start with 0x01.");
            }

            Int32 width, height;
            width = r.ReadInt32();
            height = r.ReadInt32();

            Texture2D ret = new Texture2D(device, width, height, 1, TextureUsage.None, SurfaceFormat.Color);
            List<byte> retBytes = new List<byte>();
            int size = width * height;

            XNAColor[] temp = new XNAColor[size];

            //Read in the 20 byte header of the block
            for (int i = 0; i < 20; i++)
            {
                //Discard it as we have no fucking clue what it means. We can implement
                //this later
                retBytes.Add(r.ReadByte());
            }

            byte colorIndex;
            for (int i = 0; i < size; i++)
            {
                colorIndex = r.ReadByte();

                //Maximum value that can be held by 5 bits is 31, so divide by 31 to get the colour percentage
                temp[i] = palette[colorIndex];// new XNAColor(1.0f, 1.0f, 1.0f);
            }

            ret.SetData<XNAColor>(temp);

            return new TileSetTile(ret,retBytes);
        }

        public static GD ReturnGDTexture(Texture2D texture)
        {
            int width = texture.Width;
            int height = texture.Height;

            XNAColor[] colorArray = new XNAColor[width * height];

            texture.GetData<XNAColor>(colorArray);

            GD gd = new GD(width, height, true);
            for (int x = 0; x < width; x++)
			{
                for (int y = 0; y < height; y++)
			    {
                    XNAColor currentColorXNA = colorArray[y * width + x];
                    GDColor color = gd.ColorAllocate(currentColorXNA.R, currentColorXNA.G, currentColorXNA.B);
                    gd.Fill(x, y, color);
                }
			}
            return gd;
            
        }
        public static Image ReturnImage(Texture2D texture)
        {
            int width = texture.Width;
            int height = texture.Height;

            XNAColor[] pixelArray = new XNAColor[width * height];

            texture.GetData<XNAColor>(pixelArray);
            Bitmap bitmap = new Bitmap(texture.Width, texture.Height);

            for (int x = 0; x < width; x++)
            {
                for (int y = 0; y < height; y++)
                {
                    XNAColor currentColorXNA = pixelArray[y * width + x];

                    bitmap.SetPixel(x, y, ConvertXNAColorToSystemColor(currentColorXNA));
                }
            }
            
            return (Image)bitmap;

        }  
        public static SystemColor ConvertXNAColorToSystemColor(XNAColor xnaColor)
        {
            return SystemColor.FromArgb(xnaColor.A, xnaColor.R, xnaColor.G, xnaColor.B);
        }
    }
}